# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Common utility functions to generate C++ source fragments."""

_AUTO_GENERATED_HEADER_BEGIN_TEMPLATE = (
r'''// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef {guard_macro_name}
#define {guard_macro_name}

// clang-format off
// BEGIN_AUTO_GENERATED [{script_name}] DO NOT EDIT!!
//

namespace crazy {{
namespace testing {{

''')

_AUTO_GENERATED_HEADER_END_TEMPLATE = (
r'''
}}  // namespace testing
}}  // namespace crazy

// END_AUTO_GENERATED_CODE [{script_name}]
// clang-format on

#endif  // {guard_macro_name}'''
)

def CSourceForArrayData(values, formatter, margin=4, width=80):
  """Turn an array of values into a C source array data definition.

  Args:
    values: Array of input values.
    formatter: Formatting function, applied to each input value to get a
      C-source description of the value.
    margin: Left-side margin / indentation level.
    width: Maximum line width.
  Returns:
    A string containing the data definition as a C source fragment.
  """
  read_pos = 0
  read_len = len(values)
  write_pos = margin
  line_start = ' ' * margin
  # Account for the margin + one final comma.
  max_width = width - margin - 1
  out = ''
  while read_pos < read_len:
    out += line_start
    write_pos = 0
    comma = ''
    while read_pos < read_len:
      item = comma + formatter(values[read_pos])
      if write_pos + len(item) > max_width:
        break  # Too long, break line before this item.
      out += item
      read_pos += 1
      write_pos += len(item)
      comma = ','
    if read_pos == read_len:
      break
    out += ',\n'
  return out


def CSourceForIntegerHexArray(values, num_bits, margin=4, width=80):
  """Turn an array of integers into a C source array data definition.

  Args:
    values: An array of integers.
    num_bits: The number of bits of said integers (i.e. 8, 16, 32 or 64).
    margin: Left-side margin / indentation level (must be > 0).
    width: Maximum line width.
  Returns:
    A string containing the data definition as a C source fragment.
  """
  chars_per_word = num_bits / 4
  format_str = ' 0x%%0%dx' % chars_per_word
  out = CSourceForArrayData(values, lambda x: format_str % x,
                            margin - 1, width)
  out += ',\n'
  return out


def _FormatChar(ch):
  """Convert a character into its C source description."""
  code = ord(ch)
  if code < 32 or code > 127:
    return "'\\%d'" % code
  else:
    return "'%s'" % ch


def CSourceForConstCharArray(chars, variable_name, margin=4, width=80):
  """Return C source fragment for static const char C array.

  Args:
    chars: An array or string containing all the characters for array.
    variable_name: Name of the array variable.
  Returns:
    A new string holding a C source fragment for the array definition.
  """
  out = 'static const char %s[%d] = {\n' % (variable_name, len(chars))
  out += CSourceForArrayData(chars, _FormatChar, margin, width)
  out += '};\n'
  return out


def CSourceForComments(lines):
  """Wrap the content of |lines| instead into C++ comments."""
  out = ''
  for line in lines.split('\n'):
    line = line.rstrip()
    if line:
      out += '// %s\n' % line
    else:
      out += '//\n'

  return out


def CSourceBeginAutoGeneratedHeader(script_name, guard_macro_name):
  return _AUTO_GENERATED_HEADER_BEGIN_TEMPLATE.format(
      script_name=script_name,
      guard_macro_name=guard_macro_name)


def CSourceEndAutoGeneratedHeader(script_name, guard_macro_name):
  return _AUTO_GENERATED_HEADER_END_TEMPLATE.format(
      script_name=script_name,
      guard_macro_name=guard_macro_name)
